package ciprian.google;

import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import ciprian.google.location_mgr.MapPoint;
import ciprian.google.parser.GPXXMLParser;
import ciprian.google.parser.PointsToGPX;
import android.app.Activity;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class StatsActivity extends Activity {
    protected String routeFilePath;
    protected ArrayList<MapPoint> mapPoints;

    protected Toast infoToast;

    public static class GpxStats {
        public float distance;
        public int verticalUp;
        public int verticalDown;
        public long duration;

        public GpxStats(float d, int up, int down, int dur) {
            distance = d;
            verticalUp = up;
            verticalDown = down;
            duration = dur;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.stats);

        TextView distanceTextView = (TextView) findViewById(R.id.distanceTextView);
        TextView upDistanceTextView = (TextView) findViewById(R.id.verticalUpTextView);
        TextView downDistanceTextView = (TextView) findViewById(R.id.verticalDownTextView);
        TextView durationTextView = (TextView) findViewById(R.id.durationTextView);
        TextView verticalDistanceTagTextView = (TextView) findViewById(R.id.verticalTagTextView);
        TextView durationTagTextView = (TextView) findViewById(R.id.durationTagTextView);
        TextView avgSpeedTextView = (TextView) findViewById(R.id.avgSpeedTextView);
        TextView avgSpeedTagTextView = (TextView) findViewById(R.id.avgSpeedTagTextView);

        infoToast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);

        routeFilePath = PointsToGPX.getTheRouteFilePath();

        ArrayList<MapPoint> rawMapPoints = null;
        // load the selected route file
        if (null != routeFilePath) {
            File routeFile = new File(routeFilePath);
            try {
                GPXXMLParser xmlParser = new GPXXMLParser(routeFile.toURI().toString());

                rawMapPoints = xmlParser.getPoints();
            } catch (Exception e) {
                e.printStackTrace();
                infoToast.setText(R.string.gpx_parse_error_message);
                infoToast.show();
            }
        }

        if (rawMapPoints == null || rawMapPoints.size() == 0) {
            infoToast.setText(R.string.no_intermediate_points);
            infoToast.show();

            this.finish();
            return;
        }

        mapPoints = new ArrayList<MapPoint>();
        // remove POIs, for stats we need only intermediate points
        for (MapPoint p : rawMapPoints) {
            if (p.getType() == MapPoint.INTERMEDIATE_POINT)
                mapPoints.add(p);
        }

        if (mapPoints.size() == 0) {
            infoToast.setText(R.string.no_intermediate_points);
            infoToast.show();

            this.finish();
            return;
        }

        // set the title of the activity
        if (routeFilePath != null) {
            int pos = routeFilePath.lastIndexOf('/');
            if (pos > 0) {
                this.setTitle(routeFilePath.substring(pos));
            }
        }

        GpxStats dist = computeStats(mapPoints);

        // total distance section
        if (dist.distance > 5000) {
            // display the distance in km
            DecimalFormat df = new DecimalFormat("##0.000");
            distanceTextView.setText(df.format(dist.distance / 1000) + " km");
        } else {
            // display the distance in m
            distanceTextView.setText(String.valueOf(dist.distance) + " m");
        }

        // vertical distance section
        if (dist.verticalUp > 0)
            upDistanceTextView.setText(getString(R.string.up) + " "
                    + String.valueOf(dist.verticalUp) + " m");

        if (dist.verticalDown > 0)
            downDistanceTextView.setText(getString(R.string.down) + " "
                    + String.valueOf(dist.verticalDown) + " m");

        if (dist.verticalDown == 0 || dist.verticalUp == 0) {
            // insufficient accuracy
            verticalDistanceTagTextView.setText(getString(R.string.vertical) + " "
                    + getString(R.string.altered_data_4_stats));
        }

        // Duration section
        if (dist.duration > 0) {
            int seconds;
            int minutes;
            int hours;
            int days;

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
                seconds = (int) (dist.duration / 1000) % 60;
                minutes = (int) ((dist.duration / (1000 * 60)) % 60);
                hours = (int) ((dist.duration / (1000 * 60 * 60)) % 24);
                days = (int) ((dist.duration) / (1000 * 60 * 60 * 24));
            } else {
                days = (int) TimeUnit.MILLISECONDS.toDays(dist.duration);
                hours = (int) (TimeUnit.MILLISECONDS.toHours(dist.duration) % 24);
                minutes = (int) (TimeUnit.MILLISECONDS.toMinutes(dist.duration) % 60);
                seconds = (int) (TimeUnit.MILLISECONDS.toSeconds(dist.duration) % 60);
            }

            durationTextView.setText(((days > 0) ? String.format("%d d, ", days) : "")
                    + String.format("%d:%02d:%02d", hours, minutes, seconds));
        } else {
            // insufficient accuracy
            durationTextView.setText("0:00:00");
            durationTagTextView.setText(getString(R.string.duration) + " "
                    + getString(R.string.altered_data_4_stats));
        }

        // speed section
        if (dist.distance > 0 && dist.duration > 0) {
            // we have enough data to compute the average speed
            double speed = (double) (dist.distance) / ((double) (dist.duration / 1000));
            avgSpeedTextView.setText(String.format("%.2f", speed) + " m/s");
        } else {
            avgSpeedTextView.setText("0 m/s");
            avgSpeedTagTextView.setText(getString(R.string.avg_speed) + ", "
                    + getString(R.string.altered_data_4_stats));
        }
    }

    protected GpxStats computeStats(ArrayList<MapPoint> points) {
        GpxStats ret = new GpxStats(0, 0, 0, 0);
        long minTime = (points.get(0).getTime() > 0) ? points.get(0).getTime() : Long.MAX_VALUE;
        long maxTime = (points.get(0).getTime() > 0) ? points.get(0).getTime() : Long.MIN_VALUE;

        // parse the points
        for (int i = 1; i < points.size(); i++) {
            Location src = points.get(i - 1).getLocation();
            Location dest = points.get(i).getLocation();

            ret.distance += src.distanceTo(dest);
            if (src.getAltitude() != 0 || dest.getAltitude() != 0) {
                int v = (int) (src.getAltitude() - dest.getAltitude());
                if (v > 0) {
                    ret.verticalDown += v;
                } else {
                    ret.verticalUp += Math.abs(v);
                }
            }

            if (dest.getTime() != 0) {
                if (dest.getTime() < minTime)
                    minTime = dest.getTime();

                if (dest.getTime() > maxTime)
                    maxTime = dest.getTime();
            }
        }

        // duration in milis
        if (maxTime == Long.MIN_VALUE || minTime == Long.MAX_VALUE)
            ret.duration = 0;
        else
            ret.duration = maxTime - minTime;

        return ret;
    }
}
